#include <map>
#include <mutex>
#include "socket_def.h"

namespace herm{
namespace Private{

typedef std::map<int, std::string> ErrNo2Str;
static ErrNo2Str* g_errNo2Str = nullptr;
static std::mutex g_errStrMutex;

std::string GetLastStrError(int errNo)
{
	std::lock_guard<std::mutex> guard(g_errStrMutex);
	if (!g_errNo2Str)
	{
		g_errNo2Str = new ErrNo2Str;
		g_errNo2Str->insert(std::make_pair(WSAEINTR, "Interrupted function call"));
		g_errNo2Str->insert(std::make_pair(WSAEBADF, "File handle is not valid"));
		g_errNo2Str->insert(std::make_pair(WSAEACCES, "Permission denied"));
		g_errNo2Str->insert(std::make_pair(WSAEFAULT, "Bad address"));
		g_errNo2Str->insert(std::make_pair(WSAEINVAL, "Invalid argument"));
		g_errNo2Str->insert(std::make_pair(WSAEMFILE, "Too many open files"));
		g_errNo2Str->insert(std::make_pair(WSAEWOULDBLOCK, "Resource temporarily unavailable"));
		g_errNo2Str->insert(std::make_pair(WSAEINPROGRESS, "Operation now in progress"));
		g_errNo2Str->insert(std::make_pair(WSAEALREADY, "Operation already in progress"));
		g_errNo2Str->insert(std::make_pair(WSAENOTSOCK, "Socket operation on nonsocket"));
		g_errNo2Str->insert(std::make_pair(WSAEDESTADDRREQ, "Destination address required"));
		g_errNo2Str->insert(std::make_pair(WSAEMSGSIZE, "Message too long"));
		g_errNo2Str->insert(std::make_pair(WSAEPROTOTYPE, "Protocol wrong type for socket"));
		g_errNo2Str->insert(std::make_pair(WSAENOPROTOOPT, "Bad protocol option"));
		g_errNo2Str->insert(std::make_pair(WSAEPROTONOSUPPORT, "Protocol not supported"));
		g_errNo2Str->insert(std::make_pair(WSAESOCKTNOSUPPORT, "Socket type not supported"));
		g_errNo2Str->insert(std::make_pair(WSAEOPNOTSUPP, "Operation not supported"));
		g_errNo2Str->insert(std::make_pair(WSAEPFNOSUPPORT, "Protocol family not supported"));
		g_errNo2Str->insert(std::make_pair(WSAEAFNOSUPPORT, "Address family not supported by protocol family"));
		g_errNo2Str->insert(std::make_pair(WSAEADDRINUSE, "Address already in use"));
		g_errNo2Str->insert(std::make_pair(WSAEADDRNOTAVAIL, "Cannot assign requested address"));	
		g_errNo2Str->insert(std::make_pair(WSAENETDOWN, "Network is down"));
		g_errNo2Str->insert(std::make_pair(WSAENETUNREACH, "Network is unreachable"));
		g_errNo2Str->insert(std::make_pair(WSAENETRESET, "Network dropped connection on reset"));
		g_errNo2Str->insert(std::make_pair(WSAECONNABORTED, "Software caused connection abort"));
		g_errNo2Str->insert(std::make_pair(WSAECONNRESET, "Connection reset by peer"));
		g_errNo2Str->insert(std::make_pair(WSAENOBUFS, "No buffer space available"));
		g_errNo2Str->insert(std::make_pair(WSAEISCONN, "Socket is already connected"));
		g_errNo2Str->insert(std::make_pair(WSAENOTCONN, "Socket is not connected"));
		g_errNo2Str->insert(std::make_pair(WSAESHUTDOWN, "Cannot send after socket shutdown"));
		g_errNo2Str->insert(std::make_pair(WSAETOOMANYREFS, "Too many references"));
		g_errNo2Str->insert(std::make_pair(WSAETIMEDOUT, "Connection timed out"));
		g_errNo2Str->insert(std::make_pair(WSAECONNREFUSED, "Connection refused"));
		g_errNo2Str->insert(std::make_pair(WSAELOOP, "Cannot translate name"));
		g_errNo2Str->insert(std::make_pair(WSAENAMETOOLONG, "Name too long"));
		g_errNo2Str->insert(std::make_pair(WSAEHOSTDOWN, "Host is down"));
		g_errNo2Str->insert(std::make_pair(WSAEHOSTUNREACH, "No route to host"));
		g_errNo2Str->insert(std::make_pair(WSAENOTEMPTY, "Directory not empty"));
		g_errNo2Str->insert(std::make_pair(WSAEPROCLIM, "Too many processes"));
		g_errNo2Str->insert(std::make_pair(WSAEUSERS, "User quota exceeded"));
		g_errNo2Str->insert(std::make_pair(WSAEDQUOT, "Disk quota exceeded"));
		g_errNo2Str->insert(std::make_pair(WSAESTALE, "Stale file handle reference"));
		g_errNo2Str->insert(std::make_pair(WSAEREMOTE, "Item is remote"));
		g_errNo2Str->insert(std::make_pair(WSASYSNOTREADY, "Network subsystem is unavailable"));
		g_errNo2Str->insert(std::make_pair(WSAVERNOTSUPPORTED, "Winsock.dll version out of range"));
		g_errNo2Str->insert(std::make_pair(WSANOTINITIALISED, "Successful WSAStartup not yet performed"));
		g_errNo2Str->insert(std::make_pair(WSAEDISCON, "Graceful shutdown in progress"));
		g_errNo2Str->insert(std::make_pair(WSAENOMORE, "No more results"));
		g_errNo2Str->insert(std::make_pair(WSAECANCELLED, "Call has been canceled"));
		g_errNo2Str->insert(std::make_pair(WSAEINVALIDPROCTABLE, "Procedure call table is invalid"));
		g_errNo2Str->insert(std::make_pair(WSAEINVALIDPROVIDER, "Service provider is invalid"));
		g_errNo2Str->insert(std::make_pair(WSAEPROVIDERFAILEDINIT, "Service provider failed to initialize"));
		g_errNo2Str->insert(std::make_pair(WSASYSCALLFAILURE, "System call failure"));
		g_errNo2Str->insert(std::make_pair(WSASERVICE_NOT_FOUND, "Service not found"));
	}

	ErrNo2Str::const_iterator it = g_errNo2Str->find(errNo);
	if (it != g_errNo2Str->end())
		return it->second;
	else
		return std::string("Unknow error");
}

} // end namespace Private{
} // end namespace herm{
